﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections;
using Kokomo.Environment.Commanding;
using System.Threading;
using System.Collections.ObjectModel;
using System.Windows;

namespace Kokomo.Environment.Documents
{
	public class TreeNodeViewModel : NotifierObject
	{
		public TreeNodeViewModel(
			ImageSource iconSource,
			UiString heading,
			object target = null
			)
		{
			this.IconSource = iconSource;
			this._icon = new Lazy<Image>(this.CreateIcon);
			this.Heading = heading;
			this.Target = target;
		}

		public override string ToString()
		{
			return this.Heading;
		}

		public object Target { get; set; }
		public ImageSource IconSource { get; set; }
		private Lazy<Image> _icon;
		public Image Icon
		{
			get { return this._icon.Value; }
		}
		private Image CreateIcon()
		{
			if (this.IconSource != null)
			{
				return new Image() { Source = this.IconSource };
			}
			return null;
		}

		public UiString Heading { get; private set; }

		private Func<ProgressInfo, IEnumerable<TreeNodeViewModel>> _itemsSourceDelegate;
		public Func<ProgressInfo, IEnumerable<TreeNodeViewModel>> ItemsSourceDelegate
		{
			get { return this._itemsSourceDelegate; }
			set
			{
				this._itemsSourceDelegate = value;
				if (value != null)
				{
					this._itemsSource = null;
				}

				this.OnPropertyChanged("ItemsSourceDelegate");
				this.OnPropertyChanged("ItemsSource");
			}
		}

		private ProgressInfo _loadingProgress;
		private IEnumerable _itemsSource;
		public IEnumerable ItemsSource
		{
			get
			{
				if (
					(this._itemsSource == null)
					&& (this._itemsSourceDelegate != null)
					)
				{
					this._loadingProgress = new ProgressInfo() { Text = UiString.FromString(Messages.LoadingText) };
					return new object[] { this._loadingProgress };
				}

				return this._itemsSource;
			}
			set
			{
				this._itemsSource = value;
				this.OnPropertyChanged("ItemsSource");
			}
		}

		private void BeginPopulating()
		{
			new Thread(this.PopulateAsyncProc) { Name = "TreeNodeViewModule.Populate" }.Start();
		}

		private bool _isPopulating;
		private void PopulateAsyncProc()
		{
			this._isPopulating = true;
			try
			{
				var itemsSource = this._itemsSourceDelegate(this._loadingProgress);
				if (itemsSource == null) itemsSource = new TreeNodeViewModel[0];	// This way the node knows it is populated

				ObservableCollection<TreeNodeViewModel> items = new ObservableCollection<TreeNodeViewModel>();
				this._itemsSource = items;
				this.OnPropertyChanged("ItemsSource");

				const int bufferSize = 30;
				List<TreeNodeViewModel> buffer = new List<TreeNodeViewModel>(bufferSize);
				foreach (var item in itemsSource)
				{
					buffer.Add(item);
					if (buffer.Count >= bufferSize)
					{
						items.DispatcherBeginAddRange(buffer);
						buffer = new List<TreeNodeViewModel>(bufferSize);
					}
				}
				if (buffer.Count > 0)
					items.DispatcherBeginAddRange(buffer);
			}
			finally
			{
				this._isPopulating = false;
			}

			this.OnPropertyChanged("ItemsSource");
		}

		private bool _isExpanded;
		public bool IsExpanded
		{
			get { return this._isExpanded; }
			set
			{
				this._isExpanded = value;
				if (
					(this._itemsSource == null)
					&& (this._itemsSourceDelegate != null)
					&& !this._isPopulating
					)
				{
					this.BeginPopulating();
				}

				this.OnPropertyChanged("IsExpanded");
			}
		}

		public IEnumerable<MenuItemViewModel> ContextMenuItems { get; set; }
		public bool HasContextMenu
		{
			get
			{
				bool hasContextMenu =
					(this.ContextMenuItems != null)
					&& (this.ContextMenuItems.Count() > 0)
					;
				return hasContextMenu;
			}
		}
	}
}
